/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO

Authors: Nitay Megides
		 Rachel Banino

Project: Exercise 1

Using: Hw1Types.h

Description:
A simple linked list implementation. It has, in addition to a normal linked 
list, an item count, and pointers to both the anchor, and the last item.
oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/

#include "LinkedList.h"
#include "stdlib.h"
#include "General.h"
#include <string.h>

PList InitializeList()
{
	PList list = (PList)malloc(sizeof(TList));
	AssertOutOfMemory(list);
	list->Anchor = NULL;
	list->Count = 0;
	list->Last = NULL;

	return list;
}

PListItem CreateValue(void* value)
{
	// Create the new item
	PListItem newItem = (PListItem)malloc(sizeof(TListItem));

	// Verify enough memory available
    AssertOutOfMemory(newItem);

    // Zero it out;
	newItem->NextItem = NULL;
	newItem->PrevItem = NULL;
	newItem->Value = NULL;

 	// Attach the value
	newItem->Value = value;

	return newItem;
}

PListItem AddItem(PList list, PListItem item)
{
	// Verify item if valid
	if ((item == NULL) || (list == NULL))
	{
		return NULL;
	}

	// Check if the list is empty
	if (list->Last == NULL)
	{
		// If so - Initialize on the first item
		list->Anchor = item;
	}
	else
	{
		// Not empty? Then just add the item in the end
		list->Last->NextItem = item;
		item->PrevItem = list->Last;
	}

	list->Last = item;
	list->Count++;

	return item;
}

PListItem AddValue(PList list, void* aValue)
{
    // Create an item
    PListItem newItem = CreateValue(aValue);

	// Add it to the list
	return AddItem(list, newItem);
}

/* 
 * Adds itemToInsert to the list, after itemBefore
 */
BOOL InsertItemAfter(PList list, PListItem itemBefore, PListItem itemToInsert)
{
	PListItem itemAfter;

	// Verify item if valid
	if ((itemBefore == NULL) || (itemToInsert == NULL) || (list == NULL))
	{
		return FALSE;
	}

	// Get the next item
	itemAfter = itemBefore->NextItem;

	itemBefore->NextItem = itemToInsert;
	itemToInsert->PrevItem = itemBefore;

	itemToInsert->NextItem = itemAfter;
	if (itemAfter == NULL)
		// If we're inserting at the end - Change the last
		list->Last = itemToInsert;
	else
		// If not - set the next item "prev" field
		itemAfter->PrevItem = itemToInsert;
	
	list->Count++;

    return TRUE;
}

/* 
 * Adds itemToInsert to the list, right before itemNext
 */
BOOL InsertItemBefore(PList list, PListItem itemNext, PListItem itemToInsert)
{
	PListItem itemBefore;

	// Verify item if valid
	if ((itemNext == NULL) || (itemToInsert == NULL) || (list == NULL))
	{
		return FALSE;
	}

	// Get the next item
	itemBefore = itemNext->PrevItem;

	itemNext->PrevItem = itemToInsert;
	itemToInsert->NextItem = itemNext;

	itemToInsert->PrevItem = itemBefore;
	if (itemBefore == NULL)
		// If we're inserting at the beginning - Change the anchor
		list->Anchor = itemToInsert;
	else
		// If not - set the next item "prev" field
		itemBefore->NextItem = itemToInsert;
	
	list->Count++;

    return TRUE;

}

BOOL RemoveItem(PList list, PListItem item)
{
	PListItem prev;
	PListItem next;

	// Verify
	if (item == NULL)
	{
		return FALSE;
	}
	// Get prev and next items
	prev = (PListItem)item->PrevItem;
	next = (PListItem)(item->NextItem);

	// Remove the item from the linked list 
	// (With verification on start and end)
	if (prev != NULL)
		prev->NextItem = next;
	
	if (next != NULL)
		next->PrevItem = prev;

	if (list->Last == item)
		list->Last = item->PrevItem;
	if (list->Anchor == item)
		list->Anchor = item->NextItem;

	list->Count--;

	// Free the item
	free(item->Value);
	free(item);

	return TRUE;}

PListItem GetNext(PListItem item)
{
	if (item == NULL)
		return NULL;

	return item->NextItem;
}

PListItem GetPrev(PListItem item)
{
	if (item == NULL)
		return NULL;

	return item->PrevItem;
}

BOOL FreeList(PList list)
{
	int i = 0;

	// Get the first item
	PListItem item = list->Anchor;
	PListItem next;
	while (item != NULL)
	{
		// Get the next item before we free the current one
		next = item->NextItem;

		// Remove the current one
		RemoveItem(list, item);

		// Go on to the next one
		item = next;
	}

	free(list);

	return TRUE;
}
